package com.rzgeo.rzmaplib.comp.geoview;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;

import com.esri.arcgisruntime.geometry.Envelope;
import com.esri.arcgisruntime.geometry.Point;
import com.esri.arcgisruntime.layers.ArcGISTiledLayer;
import com.esri.arcgisruntime.layers.FeatureLayer;
import com.esri.arcgisruntime.layers.Layer;
import com.esri.arcgisruntime.location.LocationDataSource;
import com.esri.arcgisruntime.mapping.ArcGISMap;
import com.esri.arcgisruntime.mapping.Basemap;
import com.esri.arcgisruntime.mapping.LayerList;
import com.esri.arcgisruntime.mapping.view.GeoView;
import com.esri.arcgisruntime.mapping.view.GraphicsOverlay;
import com.esri.arcgisruntime.mapping.view.LocationDisplay;
import com.esri.arcgisruntime.mapping.view.MapView;
import com.esri.arcgisruntime.util.ListenableList;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by zhanghang on 2018/1/20.
 */

public class RmlMapViewHolder implements IRmlGeoViewHolder {

    private final MapView _mapView;
    private MapViewLocMgr _mapViewLocMgr;

    public RmlMapViewHolder(MapView mapView){
        _mapView=mapView;
        _mapView.setAttributionTextVisible(false);
    }

    @Override
    public ILocMgr getLocMgr() {
        if(_mapViewLocMgr==null){
            _mapViewLocMgr=new MapViewLocMgr();
        }
        return _mapViewLocMgr;
    }

    @Override
    public void onMapTouch(OnTouchListener onTouchListener) {

    }

    @Override
    public void addGraphicsOverlay(GraphicsOverlay gls) {
        _mapView.getGraphicsOverlays().add(gls);
    }

    @Override
    public void setViewPoint(Point llPoint) {
        _mapView.setViewpointCenterAsync(llPoint, 50000);
    }

    @Override
    public void setViewExtent(Envelope ext) {
        _mapView.setViewpointGeometryAsync(ext,0.8);
    }

    @Override
    public void setBaseMap(ArcGISTiledLayer tlayer, final String elevationSourcePath) {

        ArcGISMap map = new ArcGISMap(
                new Basemap(tlayer));
        _mapView.setMap(map);
    }

    @Override
    public void addDomLayer(ArrayList<Layer> layers) {
        _mapView.getMap().getBasemap().getBaseLayers().addAll(layers);
    }

    @Override
    public void addDemRasterLayer(ArrayList<Layer> demLayers) {
        _mapView.getMap().getOperationalLayers().addAll(demLayers);
    }

    @Override
    public GeoView getGeoView() {
        return _mapView;
    }

    @Override
    public void addRefenceLayer(Layer l) {
        _mapView.getMap().getBasemap().getReferenceLayers().add(l);
    }

    @Override
    public void adddRefenceLayers(List<FeatureLayer> ls) {
        _mapView.getMap().getBasemap().getReferenceLayers().addAll(ls);
    }

    @Override
    public void addOptionLayer(FeatureLayer l) {
        _mapView.getMap().getOperationalLayers().add(l);
    }

    @Override
    public void addOptionLayers(List<FeatureLayer> ls) {
        _mapView.getMap().getOperationalLayers().addAll(ls);
    }

    @Override
    public LayerList getBaseLayers() {
        return _mapView.getMap().getBasemap().getBaseLayers();
    }

    @Override
    public LayerList getOperationalLayers() {
        return _mapView.getMap().getOperationalLayers();
    }

    @Override
    public ListenableList<GraphicsOverlay> getGraphicsOverlays() {
        return _mapView.getGraphicsOverlays();
    }

    @Override
    public LayerList getRefrenceLayers() {
        return _mapView.getMap().getBasemap().getReferenceLayers();
    }

    private class MapViewLocMgr implements ILocMgr, LocationDisplay.LocationChangedListener {
        private final SensorEventListener _sensorEventListener;
        private boolean _isStarted;
        private OnRecodeResult _onRecodeResult;

        public MapViewLocMgr() {

            _sensorEventListener=new SensorEventListener() {

                public void onSensorChanged(SensorEvent event) {
                    if (Sensor.TYPE_ACCELEROMETER != event.sensor.getType()) {
                        return;
                    }

                    _accelerometer = event.values;
                }

                public void onAccuracyChanged(Sensor sensor, int accuracy) {

                }
            };
        }

        private LocationDataSource.Location _lastLoc;
        private float[] _accelerometer;
        Queue<Info> queue = new LinkedList<>();
        private int _size;
        private boolean _withAttitude;

        @Override
        public void start(boolean withAttitude, int interval, int size, OnRecodeResult onRecodeResult) {
            queue = new LinkedList<>();
            _withAttitude=withAttitude;
            _onRecodeResult=onRecodeResult;

            _accelerometer=null;
            _lastLoc=null;
            _size=size;

            _isStarted=_mapView.getLocationDisplay().isStarted();
            if(!_isStarted)
                _mapView.getLocationDisplay().stop();

            _mapView.getLocationDisplay().addLocationChangedListener(this);
            if(_withAttitude)
                startAttitude();

            Timer timer=new Timer();
            TimerTask tk=new TimerTask() {
                @Override
                public void run() {

                    Info info=null;
                    if(_withAttitude){
                        if(_lastLoc!=null&&_accelerometer!=null)
                            info=new Info(new Date(),_lastLoc,_accelerometer);
                    }else{
                        if(_lastLoc!=null)
                            info=new Info(new Date(),_lastLoc,null);
                    }

                    if(info!=null){
                        if(queue.size()==_size)
                            queue.remove();
                        queue.add(info);
                    }
                }
            };
            timer.schedule(tk,100);

        }

        @Override
        public void onLocationChanged(LocationDisplay.LocationChangedEvent e) {
            _lastLoc=e.getLocation();
        }

        private void startAttitude() {
            SensorManager sm = (SensorManager) _mapView.getContext().getSystemService(Context.SENSOR_SERVICE);
            sm.registerListener(_sensorEventListener, sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
        }

        @Override
        public void stop() {
            if(_withAttitude){
                SensorManager sm = (SensorManager) _mapView.getContext().getSystemService(Context.SENSOR_SERVICE);
                sm.unregisterListener(_sensorEventListener, sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER));
            }
            _mapView.getLocationDisplay().removeLocationChangedListener(this);
            if(!_isStarted)
                _mapView.getLocationDisplay().stop();

            _onRecodeResult.onFinish(queue);
        }

    }
}
